# RUN: llc -march=amdgcn -mcpu=gfx900 -run-pass si-mode-register  %s -o - | FileCheck %s

---
# check that the mode is changed to rtz from default rtn for interp f16
# CHECK-LABEL: name: interp_f16_default
# CHECK-LABEL: bb.0:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK-NEXT: V_INTERP_P1LL_F16
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK-NEXT: V_ADD_F16_e32
# CHECK-NOT: S_SETREG_IMM32_B32

name: interp_f16_default

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2
    $m0 = S_MOV_B32 killed $sgpr2
    $vgpr0 = V_MOV_B32_e32 killed $sgpr0, implicit $exec, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr2 = V_MOV_B32_e32 killed $sgpr1, implicit $exec
    $vgpr0 = V_INTERP_P1LL_F16 0, killed $vgpr0, 2, 1, -1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr1 = V_INTERP_P2_F16 0, $vgpr2, 2, 1, 0, killed $vgpr1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr0 = V_INTERP_P2_F16 0, killed $vgpr2, 2, 1, 0, killed $vgpr0, -1, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr0 = V_ADD_F16_e32 killed $vgpr1, killed $vgpr0, implicit $mode, implicit $exec
    S_ENDPGM 0
...
---
# check that the mode is not changed for interp f16 when the mode is already RTZ
# CHECK-LABEL: name: interp_f16_explicit_rtz
# CHECK-LABEL: bb.0:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK-NEXT: V_MOV_B32_e32
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK-NEXT: V_ADD_F16_e32
# CHECK-NOT: S_SETREG_IMM32_B32

name: interp_f16_explicit_rtz

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2
    $m0 = S_MOV_B32 killed $sgpr2
    S_SETREG_IMM32_B32 3, 2177, implicit-def $mode, implicit $mode
    $vgpr0 = V_MOV_B32_e32 killed $sgpr0, implicit $exec, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr2 = V_MOV_B32_e32 killed $sgpr1, implicit $exec
    $vgpr0 = V_INTERP_P1LL_F16 0, killed $vgpr0, 2, 1, -1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr1 = V_INTERP_P2_F16 0, $vgpr2, 2, 1, 0, killed $vgpr1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr0 = V_INTERP_P2_F16 0, killed $vgpr2, 2, 1, 0, killed $vgpr0, -1, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr0 = V_ADD_F16_e32 killed $vgpr1, killed $vgpr0, implicit $mode, implicit $exec
    S_ENDPGM 0
...
---
# check that explicit RTN mode change is registered
# CHECK-LABEL: name: explicit_rtn
# CHECK-LABEL: bb.0:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK-NEXT: V_INTERP_P1LL_F16
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK-NEXT: V_ADD_F16_e32
# CHECK-NOT: S_SETREG_IMM32_B32

name: explicit_rtn

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2
    $m0 = S_MOV_B32 killed $sgpr2
    $vgpr0 = V_MOV_B32_e32 killed $sgpr0, implicit $exec, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr2 = V_MOV_B32_e32 killed $sgpr1, implicit $exec
    $vgpr0 = V_INTERP_P1LL_F16 0, killed $vgpr0, 2, 1, -1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr1 = V_INTERP_P2_F16 0, $vgpr2, 2, 1, 0, killed $vgpr1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr0 = V_INTERP_P2_F16 0, killed $vgpr2, 2, 1, 0, killed $vgpr0, -1, 0, implicit $mode, implicit $m0, implicit $exec
    S_SETREG_IMM32_B32 0, 2177, implicit-def $mode, implicit $mode
    $vgpr0 = V_ADD_F16_e32 killed $vgpr1, killed $vgpr0, implicit $mode, implicit $exec
    S_ENDPGM 0
...
---
# check that the mode is unchanged from RTN for F64 instruction
# CHECK-LABEL: name: rtn_default
# CHECK-LABEL: bb.0:
# CHECK-NOT: S_SETREG_IMM32_B32
# CHECK: V_FRACT_F64

name: rtn_default

body: |
  bb.0:
    liveins: $vgpr1_vgpr2
    $vgpr1_vgpr2 = V_FRACT_F64_e32 killed $vgpr1_vgpr2, implicit $mode, implicit $exec
    S_ENDPGM 0
...
---
# check that the mode is changed from RTZ to RTN for F64 instruction
# CHECK-LABEL: name: rtn_from_rtz
# CHECK-LABEL: bb.0:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK-NEXT: S_SETREG_IMM32_B32 0, 2177
# CHECK-NEXT: V_FRACT_F64
# CHECK-NOT: S_SETREG_IMM32_B32

name: rtn_from_rtz

body: |
  bb.0:
    liveins: $vgpr1_vgpr2
    S_SETREG_IMM32_B32 3, 2177, implicit-def $mode, implicit $mode
    $vgpr1_vgpr2 = V_FRACT_F64_e32 killed $vgpr1_vgpr2, implicit $mode, implicit $exec
    S_ENDPGM 0
...
---
# CHECK-LABEL: name: rtz_from_rtn
# CHECK-LABEL: bb.1:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK-NOT: S_SETREG_IMM32_B32

name: rtz_from_rtn

body: |
  bb.0:
    successors: %bb.1
    liveins: $vgpr1_vgpr2
    $vgpr1_vgpr2 = V_FRACT_F64_e32 killed $vgpr1_vgpr2, implicit $mode, implicit $exec
    S_BRANCH %bb.1

  bb.1:
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    S_ENDPGM 0
...
---
# check that the mode is changed from RTZ to RTN for F64 instruction
# and back again for remaining interp instruction
# CHECK-LABEL: name: interp_f16_plus_sqrt_f64
# CHECK-LABEL: bb.0:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK: V_INTERP_P1LL_F16
# CHECK: V_INTERP_P1LL_F16
# CHECK: V_INTERP_P2_F16
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK: V_FRACT_F64
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK: V_INTERP_P2_F16

name: interp_f16_plus_sqrt_f64

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    $m0 = S_MOV_B32 killed $sgpr2
    $vgpr0 = V_MOV_B32_e32 $sgpr0, implicit $exec, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr2 = V_MOV_B32_e32 $sgpr1, implicit $exec, implicit $exec
    $vgpr0 = V_INTERP_P1LL_F16 0, killed $vgpr0, 2, 1, -1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr1 = V_INTERP_P2_F16 0, $vgpr2, 2, 1, 0, killed $vgpr1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr3_vgpr4 = V_FRACT_F64_e32 killed $vgpr3_vgpr4, implicit $mode, implicit $exec
    $vgpr0 = V_INTERP_P2_F16 0, killed $vgpr2, 2, 1, 0, killed $vgpr0, -1, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr0 = V_ADD_F16_e32 killed $sgpr0, killed $vgpr0, implicit $mode, implicit $exec
    S_ENDPGM 0
...
---
# check that an explicit change to the single precision mode has no effect
# CHECK-LABEL: name: single_precision_mode_change
# CHECK-LABEL: bb.0:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK: V_INTERP_P1LL_F16
# CHECK: V_INTERP_P1LL_F16
# CHECK: V_INTERP_P2_F16
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK: V_FRACT_F64
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK: V_INTERP_P2_F16

name: single_precision_mode_change

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    $m0 = S_MOV_B32 killed $sgpr2
    $vgpr0 = V_MOV_B32_e32 $sgpr0, implicit $exec, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    S_SETREG_IMM32_B32 2, 2049, implicit-def $mode, implicit $mode
    $vgpr2 = V_MOV_B32_e32 $sgpr1, implicit $exec
    $vgpr0 = V_INTERP_P1LL_F16 0, killed $vgpr0, 2, 1, -1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr1 = V_INTERP_P2_F16 0, $vgpr2, 2, 1, 0, killed $vgpr1, 0, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr3_vgpr4 = V_FRACT_F64_e32 killed $vgpr3_vgpr4, implicit $mode, implicit $exec
    $vgpr0 = V_INTERP_P2_F16 0, killed $vgpr2, 2, 1, 0, killed $vgpr0, -1, 0, implicit $mode, implicit $m0, implicit $exec
    $vgpr0 = V_ADD_F16_e32 killed $sgpr0, killed $vgpr0, implicit $mode, implicit $exec
    S_ENDPGM 0
...
---
# check that mode is propagated back to start of loop - first instruction is RTN but needs
# setreg as RTZ is set in loop
# CHECK-LABEL: name: loop
# CHECK-LABEL: bb.1:
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK: V_FRACT_F64
# CHECK-LABEL: bb.2:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK: V_INTERP_P1LL_F16
# CHECK-NOT: S_SETREG_IMM32_B32

name: loop

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    successors: %bb.1
    $m0 = S_MOV_B32 killed $sgpr2
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2
    $vgpr3_vgpr4 = V_FRACT_F64_e32 killed $vgpr3_vgpr4, implicit $mode, implicit $exec
    S_BRANCH %bb.2

  bb.2:
    successors: %bb.1, %bb.3
    $vgpr0 = V_MOV_B32_e32 $sgpr0, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    S_CBRANCH_VCCZ %bb.1, implicit $vcc
    S_BRANCH %bb.3

  bb.3:
    S_ENDPGM 0
...
---
# two back-edges to same node with different modes
# CHECK-LABEL: name: double_loop
# CHECK-NOT: S_SETREG_IMM32_B32
# CHECK-LABEL: bb.2:
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK: V_FRACT_F64_e32
# CHECK-LABEL: bb.4:
# CHECK: S_SETREG_IMM32_B32 3, 2177

name: double_loop

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    successors: %bb.1
    $m0 = S_MOV_B32 killed $sgpr2
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2
    S_NOP 1
    S_BRANCH %bb.2

  bb.2:
    successors: %bb.1, %bb.3
    $vgpr3_vgpr4 = V_FRACT_F64_e32 killed $vgpr3_vgpr4, implicit $mode, implicit $exec
    S_CBRANCH_VCCZ %bb.1, implicit $vcc
    S_BRANCH %bb.3

  bb.3:
    successors: %bb.4
    S_NOP 1
    S_BRANCH %bb.4

  bb.4:
    successors: %bb.5
    S_NOP 1
    S_BRANCH %bb.5

  bb.5:
    successors: %bb.1, %bb.6
    S_SETREG_IMM32_B32 3, 2177, implicit-def $mode, implicit $mode
    S_CBRANCH_VCCZ %bb.1, implicit $vcc
    S_BRANCH %bb.6

  bb.6:
    S_ENDPGM 0
...
---
# check that mode is propagated back to start of loop and through a block that
# neither sets or uses the mode.
# CHECK-LABEL: name: loop_indirect
# CHECK_NOT: S_SETREG_IMM32_B32
# CHECK-LABEL: bb.3:
# CHECK: S_SETREG_IMM32_B32 3, 2177
# CHECK: V_INTERP_P1LL_F16
# CHECK-NOT: S_SETREG_IMM32_B32

name: loop_indirect

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    successors: %bb.1
    $m0 = S_MOV_B32 killed $sgpr2
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2
    S_NOP 1
    S_BRANCH %bb.2

  bb.2:
    successors: %bb.3
    S_NOP 1
    S_BRANCH %bb.3

  bb.3:
    successors: %bb.1, %bb.4
    $vgpr0 = V_MOV_B32_e32 $sgpr0, implicit $exec, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    S_CBRANCH_VCCZ %bb.1, implicit $vcc
    S_BRANCH %bb.4

  bb.4:
    S_ENDPGM 0
...
---
# check that multiple mode values are propagated to a block that uses the mode
# CHECK-LABEL: name: multiple_mode_direct
# CHECK-LABEL: bb.3:
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK: V_FRACT_F64_e32
# CHECK-NOT: S_SETREG_IMM32_B32

name: multiple_mode_direct

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    successors: %bb.1
    $m0 = S_MOV_B32 killed $sgpr2
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2, %bb.3
    S_CBRANCH_VCCZ %bb.2, implicit $vcc
    S_BRANCH %bb.3

  bb.2:
    successors: %bb.3
    S_SETREG_IMM32_B32 3, 2177, implicit-def $mode, implicit $mode
    S_BRANCH %bb.3

  bb.3:
    successors: %bb.4
    $vgpr3_vgpr4 = V_FRACT_F64_e32 killed $vgpr3_vgpr4, implicit $mode, implicit $exec
    S_BRANCH %bb.4

  bb.4:
    S_ENDPGM 0
...
---
# check that multiple mode values are propagated through a block that neither
# sets or uses the mode.
# CHECK-LABEL: name: multiple_mode_indirect
# CHECK-LABEL: bb.4:
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK: V_FRACT_F64_e32
# CHECK-NOT: S_SETREG_IMM32_B32

name: multiple_mode_indirect

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    successors: %bb.1
    $m0 = S_MOV_B32 killed $sgpr2
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2, %bb.3
    S_CBRANCH_VCCZ %bb.2, implicit $vcc
    S_BRANCH %bb.3

  bb.2:
    successors: %bb.3
    S_SETREG_IMM32_B32 3, 2177, implicit-def $mode, implicit $mode
    S_BRANCH %bb.3

  bb.3:
    successors: %bb.4
    S_NOP 1
    S_BRANCH %bb.4

  bb.4:
    successors: %bb.5
    $vgpr3_vgpr4 = V_FRACT_F64_e32 killed $vgpr3_vgpr4, implicit $mode, implicit $exec
    S_BRANCH %bb.5

  bb.5:
    S_ENDPGM 0
...
---
# CHECK-LABEL: name: pass_through_blocks
# CHECK-LABEL: bb.0:
# CHECK: V_FRACT_F64_e32
# CHECK-NEXT: S_SETREG_IMM32_B32 3, 2177
# CHECK-NOT: S_SETREG_IMM32_B32

name: pass_through_blocks

body: |
  bb.0:
    successors: %bb.1
    liveins: $vgpr1_vgpr2
    $vgpr1_vgpr2 = V_FRACT_F64_e32 killed $vgpr1_vgpr2, implicit $mode, implicit $exec
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2
    S_BRANCH %bb.2

  bb.2:
    successors: %bb.3
    S_BRANCH %bb.3

  bb.3:
    successors: %bb.4
    S_BRANCH %bb.4

  bb.4:
    $vgpr1 = V_INTERP_P1LL_F16 0, $vgpr0, 2, 1, 0, 0, 0, implicit $mode, implicit $m0, implicit $exec
    S_ENDPGM 0
...
---
# check that multiple mode values are propagated
# CHECK-LABEL: name: if_then_else
# CHECK-LABEL: bb.3:
# CHECK: S_SETREG_IMM32_B32 0, 2177
# CHECK: V_FRACT_F64_e32
# CHECK-NOT: S_SETREG_IMM32_B32

name: if_then_else

body: |
  bb.0:
    liveins: $sgpr0, $sgpr1, $sgpr2, $vgpr3, $vgpr4
    successors: %bb.1
    $m0 = S_MOV_B32 killed $sgpr2
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2, %bb.3
    S_CBRANCH_VCCZ %bb.3, implicit $vcc
    S_BRANCH %bb.2

  bb.2:
    successors: %bb.3
    S_SETREG_IMM32_B32 3, 2177, implicit-def $mode, implicit $mode
    S_BRANCH %bb.3

  bb.3:
    successors: %bb.4
    $vgpr3_vgpr4 = V_FRACT_F64_e32 killed $vgpr3_vgpr4, implicit $mode, implicit $exec
    S_BRANCH %bb.4

  bb.4:
    S_ENDPGM 0
...
---
# checks for bug where if a block is its own predecessor it could cause mode tracking
# to produce the wrong mode, resulting in an unnecessary setreg
# CHECK-LABEL: name: single_block_loop
# CHECK-LABEL: bb.0:
# CHECK-NOT: S_SETREG

name: single_block_loop

body: |
  bb.0:
    successors: %bb.1
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.1, %bb.2
    S_CBRANCH_VCCZ %bb.1, implicit $vcc
    S_BRANCH %bb.2

  bb.2:
    successors: %bb.3
    liveins: $vgpr1_vgpr2
    $vgpr1_vgpr2 = V_FRACT_F64_e32 killed $vgpr1_vgpr2, implicit $mode, implicit $exec
    S_BRANCH %bb.3

  bb.3:
    S_ENDPGM 0
...
---
# checks for a bug where if the first block is its own predecessor the initial mode was
# not correctly propagated, resulting in an unnecessary setreg
# CHECK-LABEL: name: first_block_loop
# CHECK-LABEL: bb.0:
# CHECK-NOT: S_SETREG

name: first_block_loop

body: |
  bb.0:
    successors: %bb.0, %bb.1
    S_CBRANCH_VCCZ %bb.0, implicit $vcc
    S_BRANCH %bb.1

  bb.1:
    successors: %bb.2
    liveins: $vgpr1_vgpr2
    $vgpr1_vgpr2 = V_FRACT_F64_e32 killed $vgpr1_vgpr2, implicit $mode, implicit $exec
    S_BRANCH %bb.2

  bb.2:
    S_ENDPGM 0
...
